package com.efast.dmom.equipment.opc.client;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIArray;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.da.AccessBase;
import org.openscada.opc.lib.da.Async20Access;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.Server;

public class OPCUtil {

	private static ConcurrentHashMap<String, Item> itemsMap = new ConcurrentHashMap<String, Item>();

	private static ScheduledExecutorService sendExecutor = Executors.newSingleThreadScheduledExecutor();

	private static ScheduledExecutorService writeExecutor = Executors.newSingleThreadScheduledExecutor();

	public static void write(Item item, String val) {
		try {
			JIVariant value = new JIVariant(val);
			item.write(value);
		} catch (JIException e) {
			e.printStackTrace();
		}
	}

	public static void write(Item item, String[] snArray) {
		try {

			/** 构造写入数据 */
			Long[] integerData = new Long[snArray.length];
			for (int i = 0; i < snArray.length; i++) {
				integerData[i] = Long.valueOf(snArray[i]);
			}
			final JIArray array = new JIArray(integerData, false);
			final JIVariant value = new JIVariant(array);

			item.write(value);
		} catch (JIException e) {
			e.printStackTrace();
		}
	}

	public static Item[] buildGroup(Group group, List<String> path) throws Exception {

		Item[] items = new Item[path.size()];

		if (group != null && path != null) {

			for (int i = 0; i < path.size(); i++) {
				items[i] = group.addItem(path.get(i));
				itemsMap.put(path.get(i), items[i]);
			}
		}
		return items;
	}

	public static void stopHeartBeatReader() {
		writeExecutor.shutdown();
	}

	public static void stopHeartBeatSender() {
		sendExecutor.shutdown();
	}

	public static void readHeartBeat(Item item) throws Exception {
		
		writeExecutor.scheduleWithFixedDelay(new Runnable() {
			public void run() {
				try {
					String status = getValue(item.read(true));
					
					//TODO
					System.out.println(status);

				} catch (JIException e) {
					e.printStackTrace();
				}
			}
		}, 5, 3, TimeUnit.SECONDS);
		
	}

	public static void sendHeartBeat(Item item) throws Exception {

		final JIVariant value = new JIVariant(new AtomicInteger(0).intValue());

		stopHeartBeatReader();

		sendExecutor.scheduleWithFixedDelay(new Runnable() {
			public void run() {

				try {
					System.out.println(">>> " + "writing value " + value);
					item.write(value);
				} catch (JIException e) {
					e.printStackTrace();
				}
			}
		}, 5, 3, TimeUnit.SECONDS);
	}

	public void simulateWrite(Server server) throws Exception {

		Group groupA = server.addGroup(OPCElement.GROUP1);

		Item item = groupA.addItem(OPCElement.EQUIP1_STATUS);

		ScheduledExecutorService writeThread = Executors.newSingleThreadScheduledExecutor();
		final AtomicInteger i = new AtomicInteger(0);
		writeThread.scheduleWithFixedDelay(new Runnable() {
			public void run() {
				final JIVariant value = new JIVariant(i.incrementAndGet());
				try {
					System.out.println(">>> " + "writing value " + i.get());
					item.write(value);
				} catch (JIException e) {
					e.printStackTrace();
				}
			}
		}, 5, 3, TimeUnit.SECONDS);
	}

	public static void asyncRead(Server server) throws Exception {

		AccessBase access = new Async20Access(server, 1000, false);
		access.addItem(OPCElement.EQUIP6_STATUS, new DataCallback() {
			@Override
			public void changed(Item item, ItemState itemState) {
				System.out.println(">>> Asynchronized read: value = " + itemState.getValue());
			}
		});
		access.bind();
	}

	public static List<OPCEquipBean> read(Map<Group, Item[]> groupItems) {

		List<OPCEquipBean> beanList = new ArrayList<OPCEquipBean>();

		groupItems.forEach((group, items) -> {
			try {
				Map<Item, ItemState> stateMap = group.read(true, items);

				int count = items.length / 5;
				for (int i = 0; i < count; i++) {
					OPCEquipBean bean = new OPCEquipBean();

					bean.setEquipName(getValue(stateMap.get(items[(i * 5)])));
					bean.setEquipCode(getValue(stateMap.get(items[(i * 5 + 1)])));
					bean.setEquipStatus(getValue(stateMap.get(items[(i * 5 + 2)])));
					bean.setEquipId(getValue(stateMap.get(items[(i * 5 + 3)])));
					bean.setEquipId(getValue(stateMap.get(items[(i * 5 + 4)])));

					beanList.add(bean);
				}
			} catch (JIException ex) {
				ex.printStackTrace();
			}
		});
		return beanList;
	}

	public static Item getItem(String path) {

		return itemsMap.get(path);
	}

	public static String getValue(ItemState state) throws JIException {
		String result = "";

		int type = state.getValue().getType();

		if (type == JIVariant.VT_UI4) {
			int value = state.getValue().getObjectAsInt();
			return value + "";
		} else if (type == JIVariant.VT_I2) {
			short value = state.getValue().getObjectAsShort();
			return value + "";
		} else if (type == 8195) {
			JIArray jarr = state.getValue().getObjectAsArray();
			Integer[] arr = (Integer[]) jarr.getArrayInstance();
			String value = "";
			for (Integer i : arr) {
				value = value + i + ".";
			}
			String res = value.substring(0, value.length() - 1);
			// "25.36087601.1.1.18.36"-->"25.36087601.01.0001.18.36"
			String[] array = res.split("[.]");
			String ress = array[0] + "." + array[1] + "." + new DecimalFormat("00").format(Long.valueOf(array[2])) + "."
					+ new DecimalFormat("0000").format(Long.valueOf(array[3])) + "." + array[4] + "." + array[5];
			return ress;

		} else if (type == 8196) {
			JIArray jarr = state.getValue().getObjectAsArray();
			Float[] arr = (Float[]) jarr.getArrayInstance();
			String value = "";
			for (Float f : arr) {
				value = value + f + ",";
			}
			return value.substring(0, value.length() - 1);
		} else if (type == JIVariant.VT_BSTR) {

			String strObj = state.getValue().getObjectAsString() + "";
			String[] parts = strObj.split(",");

			if (parts.length == 2 && parts[1].trim().length() >= 2) {
				String name = parts[1].trim();
				result = name.substring(1, name.indexOf("]"));
			}
		}

		return result;
	}
}
